package com.hliushi.redis.controller;

import com.hliushi.redis.entity.CartPage;
import com.hliushi.redis.entity.CookieCart;
import com.hliushi.redis.service.IdGenerator;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * @author llhuang10
 * @date 2021/8/7 20:17
 */
@Slf4j
@Api(description = "未登录下操作cookie和登录下合并cookie")
@RestController
@RequestMapping("/cookie-cart")
public class CookieCartController {


    public static final String COOKIE_KEY = "cart:cookie:";
    @Resource
    private RedisTemplate<String, Integer> redisTemplate;
    @Resource
    private IdGenerator idGenerator;
    @Resource
    private HttpServletResponse response;
    @Resource
    private HttpServletRequest request;

    /**
     * 未登录状态下添加购物车
     *
     * @param
     * @return
     */
    @ApiOperation("未登录状态下添加购物车")
    @PostMapping("/add-cart")
    public void addCart(CookieCart cookieCart) {
        String cartId = this.getCookieCartId();
        String key = COOKIE_KEY + cartId;

        Boolean hasKey = redisTemplate.opsForHash().getOperations().hasKey(key);

        if (hasKey) {
            redisTemplate.opsForHash().put(key, cookieCart.getProductId().toString(), cookieCart.getAmount());
        } else {
            redisTemplate.opsForHash().put(key, cookieCart.getProductId().toString(), cookieCart.getAmount());
            redisTemplate.expire(key, 90, TimeUnit.DAYS);
        }
    }


    /**
     * 修改购物车数量
     *
     * @param
     * @return
     */
    @ApiOperation("修改购物车数量")
    @PutMapping("/update-cart")
    public void updateCart(CookieCart cookieCart) {
        String cartId = this.getCookieCartId();
        String key = COOKIE_KEY + cartId;
        redisTemplate.opsForHash().put(key, cookieCart.getProductId().toString(), cookieCart.getAmount());
    }

    /**
     * 删除购物车
     *
     * @param
     * @return
     */
    @ApiOperation("删除购物车")
    @DeleteMapping("/del-cart")
    public void deleteCart(Long productId) {
        String cartId = this.getCookieCartId();
        String key = COOKIE_KEY + cartId;
        redisTemplate.opsForHash().delete(key, productId.toString());
    }


    /**
     * 查询某个用户的购物车
     *
     * @return
     */
    @ApiOperation("查询某个用户的购物车")
    @GetMapping("/find-all")
    public ResponseEntity<CartPage<CookieCart>> findAll() {
        String cartId = this.getCookieCartId();
        String key = COOKIE_KEY + cartId;

        CartPage<CookieCart> cartPage = new CartPage<>();
        // 查询该用户购物车的总数
        long size = redisTemplate.opsForHash().size(key);
        cartPage.setCount((int) size);

        // 查询购物车的所有商品
        Map<Object, Object> map = redisTemplate.opsForHash().entries(key);
        List<CookieCart> cartList = new ArrayList<>();
        for (Map.Entry<Object, Object> entry : map.entrySet()) {
            CookieCart cookieCart = new CookieCart();
            if (entry.getKey() instanceof String) {
                cookieCart.setProductId(Long.parseLong((String) entry.getKey()));
            }
            if (entry.getValue() instanceof Integer) {
                cookieCart.setAmount((Integer) entry.getValue());
            }
            cartList.add(cookieCart);
        }
        cartPage.setCartList(cartList);
        return ResponseEntity.ok(cartPage);
    }

    /**
     * 用户第二次登录触发, 合并购物车, 会把cookie中的购物车合并到登录用户的购物车
     *
     * @param
     * @return
     */
    @ApiOperation("用户第二次登录触发, 合并购物车")
    @PostMapping("/merge-cart")
    public void merge(Long userId) {
        // 第一步: 提取为登录用户的cookie的购物车数据
        String cartId = this.getCookieCartId();
        String keyCookie = COOKIE_KEY + cartId;
        Map<Object, Object> map = redisTemplate.opsForHash().entries(keyCookie);

        // 第二步: 把cookie中的购物车合并到登录用户的购物车
        String keyUser = "cart:user:" + userId;

        // Map<String, Integer> newMap = new HashMap<>();
        //
        // for (Map.Entry<Object, Object> entry : map.entrySet()) {
        //     if (entry.getKey() instanceof String && entry.getValue() instanceof Integer) {
        //         newMap.put((String) entry.getKey(), (Integer) entry.getValue());
        //     }
        // }

        // 当第一次登录时添加的商品, 和未登录时添加的商品有一样的商品时, 需要相加
        // 判断 未登录的情况是否添加一开始登录的购物车一样的商品 标识
        boolean flag = false;
        Map<Object, Object> userMap = redisTemplate.opsForHash().entries(keyUser);
        for (Map.Entry<Object, Object> entry : map.entrySet()) {
            String key = (String) entry.getKey();
            Integer value = (Integer) entry.getValue();
            // 未登录情况下, 添加了和之前购物车一样的数据
            if (userMap.containsKey(key)) {
                flag = true;
                Integer userValue = (Integer) userMap.get(key);
                userValue += value;
                userMap.put(key, userValue);
            } else {
                userMap.put(key, value);
            }
        }


        if (flag) {
            redisTemplate.delete(keyUser);
            redisTemplate.opsForHash().putAll(keyUser, userMap);
        } else {
            redisTemplate.opsForHash().putAll(keyUser, map);
        }

        // 第三步: 删除redis未登录的用户cookies的购物车数据
        redisTemplate.delete(keyCookie);

        // 第四步: 删除未登录用户cookies的cartId
        Cookie cookie = new Cookie("cartId", null);
        cookie.setMaxAge(0);
        response.addCookie(cookie);
    }


    /**
     * 获取cookies
     *
     * @return cookie
     */
    private String getCookieCartId() {
        // 第一步: 先检查cookies是否有cartId
        Cookie[] cookies = request.getCookies();
        for (Cookie cookie : cookies) {
            if (cookie != null) {
                if (cookie.getName().equals("cartId")) {
                    return cookie.getValue();
                }
            }
        }

        // 第二步: cookies没有cartId, 直接生成全局Id, 并设置到cookie里面
        Long cartId = idGenerator.incrementId();
        Cookie cookie = new Cookie("cartId", String.valueOf(cartId));
        response.addCookie(cookie);

        return cartId + "";
    }

}
